﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace CRFEncoder
{
    class CRFEncoderThread
    {
        public List<TaggerImpl> x;
        public int start_i;
        public int thread_num;
        public int zeroone;
        public int err;
        public int size;
        public float obj;
        public BigArray<float> expected;
        public Node[,] node_;
        public Path[] path_cache_;
        short[] result_;
        public short max_xsize_;
        public LBFGS lbfgs;

        public int[,] merr;
        public int[] yfreq;

        public void Init()
        {
            if (x.Count == 0)
            {
                return;
            }

            max_xsize_ = 0;
            for (int i = start_i; i < size; i += thread_num)
            {
                if (max_xsize_ < x[i].xsize_)
                {
                    max_xsize_ = x[i].xsize_;
                }
            }

            short ysize_ = x[0].ysize_;
            result_ = new short[max_xsize_];
            node_ = new Node[max_xsize_, ysize_];
            path_cache_ = new Path[(max_xsize_ - 1) * ysize_ * ysize_];
            for (int i = 0; i < max_xsize_; i++)
            {
                for (int j = 0; j < ysize_; j++)
                {
                    node_[i, j].lpath_id = new int[ysize_];
                    node_[i, j].rpath_id = new int[ysize_];
                }
            }

            merr = new int[ysize_, ysize_];
            yfreq = new int[ysize_];
        }

        public void Run()
        {
            //Initialize thread self data structure
            obj = 0.0f;
            err = zeroone = 0;
            expected.Clear();
            Array.Clear(merr, 0, merr.Length);
            Array.Clear(yfreq, 0, yfreq.Length);

            for (int i = start_i; i < size; i += thread_num)
            {
                x[i].Init(ref result_, ref node_, ref path_cache_);
                obj += x[i].gradient(ref expected);
                int error_num = x[i].eval(merr, yfreq);
                err += error_num;
                if (error_num > 0)
                {
                    ++zeroone;
                }
            }
        }

    }
}
